package com.onpositive.knowledge.model.values;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;

import com.onpositive.knowledge.model.value.audits.AbstractAuditResult;
import com.onpositive.knowledge.model.value.audits.GeneralAuditResult;
import com.onpositive.knowledge.model.value.audits.IdentValueSplitterAudit;
import com.onpositive.knowledge.model.value.audits.IdentValueSplitterAudit.OwnAuditResult;
import com.onpositive.semantic.model.api.property.IProperty;
import com.onpositive.units.ParsedSentence;
import com.onpositive.units.ParsedString;
import com.onpositive.units.ParsedValue;
import com.onpositive.units.ParsedValueSequence;
import com.onpositive.units.ParsedValueSequenceV2;
import com.onpositive.units.ValueCluster;

public class IdentValueSplitterTransformer extends AuditAssistedTransformer {

	private static final long serialVersionUID = -1070426168300984555L;
	public static final String ID = "Ident-splitter-transformer" ; 

	public IdentValueSplitterTransformer(IHasAuditResult src) {
		super(src);
	}

	@Override
	public DescribedValue[] adjust(Object object, IProperty prop, DescribedValue... original) {

		String name = prop.getMeta().getSingleValue( "id", String.class, null ) ;	
		
		AbstractAuditResult aResult = this.getAuditResultSource().getAuditResult() ;
		
		IdentValueSplitterAudit.OwnAuditResult auditResult = null ;
		
		if( aResult instanceof IdentValueSplitterAudit.OwnAuditResult )
			auditResult = (IdentValueSplitterAudit.OwnAuditResult)aResult ;

		else if( aResult instanceof GeneralAuditResult )
		{
			GeneralAuditResult gResult = (GeneralAuditResult) aResult ;
			AbstractAuditResult result = gResult.getResult( IdentValueSplitterAudit.ID );
			if(  !(result instanceof IdentValueSplitterAudit.OwnAuditResult))
				return original ;
			auditResult = (IdentValueSplitterAudit.OwnAuditResult) result ;			
		}
		
		if( auditResult == null )
			return original ;
		
		HashMap<String,Object> metaInfo = new HashMap<String, Object>() ;
		metaInfo.put("audit-result", auditResult ) ;
		
		Object newValuesArrayObject = sentenceSplittingTraverser.iterateValues(prop, original, false, metaInfo, 0, false ) ;		
		if( newValuesArrayObject == null )
			return original ;
		
		return (DescribedValue[]) newValuesArrayObject ;
	}
	
	ModifyingValueTraverser sentenceSplittingTraverser = new ModifyingValueTraverser() {
		
		@Override
		protected Object process(IProperty prop, Object val, Map<String, Object> metaInfo, int index, boolean cameFromCollection )
		{
			if( val instanceof ValueCluster<?> ){
				ValueCluster<?> vc = (ValueCluster<?>) val ;
				ParsedValue[] arr = vc.getValuesArray() ; 
				int targetInd = ValueCluster.computeTargetInd(vc) ;
				int off = 0 ;
				int length = arr.length ;
				
				if( IdentValueSplitterAudit.isBadValue( arr[0] ) ){
					off++ ;
					length-- ;
					targetInd-- ;
				}
				
				if( IdentValueSplitterAudit.isBadValue( arr[ arr.length-1] ) ){
					length-- ;
				}
				
				if( length == arr.length )
					return null ;
				
				ParsedValue[] newArr = new ParsedValue[length] ;
				System.arraycopy(arr, off, newArr, 0, length) ;
				
				return new ValueCluster( newArr, vc.getTargetClass(), targetInd, ID, null ) ;
				
			}
			if( val instanceof ParsedSentence )
			{			
				Object auditObject = metaInfo.get("audit-result") ;
				if(auditObject == null)
					return null;
				
				IdentValueSplitterAudit.OwnAuditResult result = (OwnAuditResult) auditObject ;			
				HashMap<String, ParsedValue[]> correctionsMap = result.getCorrectionsMap(prop.getId());
				if( correctionsMap == null )
					return null ;
				
				ParsedSentence ps = (ParsedSentence) val ;
				String key = ps.getContentString() ;
				ParsedValue[] array = correctionsMap.get(key) ;				
				
				if( array == null || array.length == 0 )
					return null ;
				
				if( cameFromCollection ){
//					
//					int l = array.length ;
//					int off = 0 ;
//					if( prefix != null ){						
//						l++ ;
//						off= 1 ;
//					}
//					if( postfix != null )
//						l++ ;
//					
//					if( l == array.length )					
//						return array ;
//					
//					ParsedValue[] newArr = new ParsedValue[l] ;
//					if(prefix != null)
//						newArr[0] = new ParsedString(prefix, ID ) ;
//					
//					if(postfix != null)
//						newArr[l-1] = new ParsedString(postfix, ID ) ;
					
//					System.arraycopy(array, 0, newArr, off, array.length ) ;
					return array ;
					//return newArr ;
				}				
				String prefix = ps.getPrefix() ;
				String postfix = ps.getPostfix() ;				
				return new ParsedValueSequenceV2( array,ID, new String[]{ prefix, postfix} ) ;
			}
			else if( val instanceof ParsedValueSequenceV2 ){
				
				ParsedValueSequenceV2 pvsv2 = (ParsedValueSequenceV2) val ;
				ParsedValue[] valArr = pvsv2.getValuesArray() ;
				
				boolean gotChange = false ;
				ParsedValue[] newValArr = (ParsedValue[]) iterateValues(prop, valArr, false, metaInfo, 0, false) ;
				
				if( newValArr != null )
					gotChange = true ;
				else
					newValArr = valArr ;
				
				ParsedValue[] sorted = sort( prop, newValArr, metaInfo ) ;
				
				if( sorted != null )
					gotChange = true ;
				else
					sorted = newValArr ;
				
				if( !gotChange )
					return null ;
				
				ParsedValue[] finalArray = IdentValueSplitterAudit.killParasiteStrings(sorted) ;
				
				return new ParsedValueSequenceV2(finalArray, ID, new String[]{ pvsv2.getPrefix(), pvsv2.getPostfix() }  ) ;
			}			
			return null ;
		}
		
		private ParsedValue[] sort( IProperty prop, ParsedValue[] array, Map<String, Object> metaInfo ) {
			
			IdentValueSplitterAudit.OwnAuditResult result = (OwnAuditResult) metaInfo.get("audit-result") ;			
			HashMap<String,Integer> weightsMap = result.getWeightsMap( prop.getId() ) ;
			if( weightsMap == null )
				return null ;
			
			IdentValueSplitterAudit.IdentComparator comp  = new IdentValueSplitterAudit.IdentComparator( weightsMap );
			
			int l = array.length;
			ParsedValue[] newArray = new ParsedValue[l] ;
			System.arraycopy(array, 0, newArray, 0, l) ;
			Arrays.sort( newArray, comp ) ;

			if( array.equals(newArray))
				return null ;
			
			return newArray;
		}

		@Override
		protected Class<?>[] createTargetClasses() {
			return new Class<?>[]{ ParsedValueSequenceV2.class, ParsedSentence.class } ;
		}
		
		@Override
		protected Class<?>[] createNecessaryClasses() {
			return new Class<?>[]{ ParsedValueSequenceV2.class, ParsedSentence.class } ;
		}
	};	

	@Override
	public String getId() {
		return ID;
	}

}
